package com.me.common.util.security;

import com.me.common.util.io.IoUtils;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.pkcs.*;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA 加密：公钥用来公开并加密，私钥用来保留解密，且不可互换。如何理解？
 * 我要保密，所以是加密之后发出去，任何人都可以帮我加密（公开，公钥），但是解密的能力肯定要保留（私钥）
 *
 * @author ME
 * @date 2021/8/13
 */
public class RSAUtil {

    private static final String PRIVATE_KEY_PATH = "cert/rsa/private.txt";
    private static final String PUBLIC_KEY_PATH = "cert/rsa/public.txt";

    /**
     * 1024位密钥位数
     */
    public static final int SIZE_1024 = 1024;
    /**
     * 2048位密钥位数
     */
    public static final int SIZE_2048 = 2048;

    /** RSA 加密算法 */
    public static final String RSA_CIPHER = "RSA";
    /**
     * RSA/ECB/PKCS1Padding 加密算法：
     * 1，加密算法有：AES、DES、DESede（DES3）和 RSA 四种
     * 2，模式有 CBC（有向量模式）和 ECB（无向量模式），向量模式可以简单理解为偏移量，使用 CBC模式需要定义一个 IvParameterSpec对象
     * 3，填充模式:
     *      NoPadding: 加密内容不足8位用0补足8位, Cipher类不提供补位功能，需自己实现代码给加密内容添加0, 如{65,65,65,0,0,0,0,0}
     *      PKCS5Padding: 加密内容不足8位用余位数补足8位, 如{65,65,65,5,5,5,5,5}或{97,97,97,97,97,97,2,2}; 刚好8位补8位8
     */
    public static final String RSA_ECB_PKCS1_CIPHER = "RSA/ECB/PKCS1Padding";

    /** 选择的 加密算法 */
    public static final String SELECTED_ALGORITHM = RSA_ECB_PKCS1_CIPHER;

    /** map 中存储公钥的 key */
    public static final String PUBLIC_KEY = "RSAPublicKey";
    /** map 中存储私钥的 key */
    public static final String PRIVATE_KEY = "RSAPrivateKey";

    private static final Base64.Decoder DECODER64 = Base64.getDecoder();
    private static final Base64.Encoder ENCODER64 = Base64.getEncoder();

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws Exception {
        // 从 cert证书解析公钥
        // System.out.println(ENCODER64.encodeToString(getPublicKeyFromCert("cert/rsa/PublicCert.cer").getEncoded()));

        // 根据 模、指数、素数等生成私钥
        // BigInteger modulus = new BigInteger("21095724487115667236434335437109076837917441465327880386338895631988408747579146355467710835734776793903171151076633186910451124836809662392336970352080401483173223416860055285032473780205550310926284990607394308266984379521058175444502581451495426762940080606251169780080348969900112713064854900247526781782451104905149905373825063238545693657446242721189502250496898520250562926648237196513724305301649565564409933467886784081101798479970275566930844996638909969736339303938434416666586041881758556486088476776981258348774115472780333874129354253740319756914346460126910766414128807010735048309667638049128036160181");
        // BigInteger publicExponent = new BigInteger("65537");
        // BigInteger privateExponent = new BigInteger("12853401505943447341472137088044960056378554940751141976393463867447840909708758306303022130731119400603438168265880949486873428229223898393097144561528945658553030872005719938151452012105952812389909302530537896507453091515561804838098060331410712819795845990634534087437453876696849119511004791519050184221789005257852875783094151579335597163453518141018102640870153594027797878740686783374489904596909757066518532935355022421169569181406377183067984625628998456256952163777606668733469264465631899925214284819213462376337576039993590605900295610975157323091645754020266530701395887468994681845327693833615059752129");
        // BigInteger primeP = new BigInteger("162047781753755436507791626272471511666627724963168825474758359834707550819818081507627240107593334353930300842215742455431610542854571602462346062512478912706343511408135266964761113895230033707630193254121640197852575813252555115313718120019506040426231473043103320357878812770420509077489978925256512166673");
        // BigInteger primeQ = new BigInteger("130182124425327263288536743251233432718253687771664301416238577891005269920017378961070772900658250972859109899359100917543918736699242031465906752366703731701006436954605872579153940901704255282057778045992204768886636428127113923502529187827175052706662286644895131749636529086536660789432897640972769367397");
        // BigInteger primeExponentP = new BigInteger("29354887544144293181264052170633104757712503635545421609721702976298091815812140678678465516537956657305957422506146061474954306189930483000945610176665847561678291155185343995081311994204357236019128954833637676868116942413206804232791576069572542410244900559496507610795997149860876814134931867504544187905");
        // BigInteger primeExponentQ = new BigInteger("117137492978951565010986339770286029683925415687246041999413902653960064805887129977483611974179731447419041316587670798290505941729928171804393261624189680003789456142531826388035886521712924515662101887058612924321298658264124205699744361294665804936324138173084912633719366468301370016217678164825430056233");
        // BigInteger crtCoefficient = new BigInteger("44893878474038111537975892712017350216607651392800253995897570527803077595471746768301516315956698515474310817204841276329791605622785079995359452252006266117375860119170144991022763407553360531086263166957385762552704027409116736629567090958269252398434076223865220772463021231208834800207058801394175467116");
        // System.out.println(getKeyStr(getPrivateKey(modulus, publicExponent, privateExponent, primeP, primeQ,
        //             primeExponentP, primeExponentQ, crtCoefficient)));

        // 创建
        Map<String, RSAKey> keyMap = createKey(RSA_CIPHER, SIZE_2048);

        String plaintext = "这是一行需要加密的明文";

        // 从密钥文件加载 pkcs#8密钥
        Map<String, Key> keyPair = genKeyPair();
        String privateKey = getKeyStr(keyPair.get(PRIVATE_KEY));
        String publicKey = getKeyStr(keyPair.get(PUBLIC_KEY));

        // 使用公钥加密
        System.out.println("公钥加密：");
        String encrypt2 = encryptByPublicKey(plaintext, publicKey);
        System.out.println(encrypt2);

        // 使用私钥解密：
        System.out.println("私钥解密：");
        System.out.println(decryptByPrivateKey(encrypt2, privateKey));

        System.out.println("\n私钥加密：");
        String encryptedStr = encryptByPri(plaintext, privateKey);
        System.out.println(encryptedStr);
        System.out.println("公钥解密：");
        System.out.println(decryptByPub(encryptedStr, publicKey));
    }

    /**
     * 公钥加密
     *
     * @param plaintext     源数据
     * @param publicKey     公钥（Base64 编码）
     * @return              明文字节数组，加密，Base64编码，再转字符串
     */
    public static String encryptByPublicKey(String plaintext, String publicKey) {
        try {
            Cipher cipher = Cipher.getInstance(SELECTED_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
            byte[] encryptedBytes = ENCODER64.encode(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
            return new String(encryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("公钥加密失败");
        }
    }

    /**
     * 私钥解密
     *
     * @param encryptedStr  已加密数据
     * @param privateKey    私钥（Base64 编码）
     * @return              密文的字节数组，Base64解码，解密，再转字符串
     */
    public static String decryptByPrivateKey(String encryptedStr, String privateKey) {
        try {
            Cipher cipher = Cipher.getInstance(SELECTED_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
            byte[] plainBytes = cipher.doFinal(DECODER64.decode(encryptedStr.getBytes(StandardCharsets.UTF_8)));
            return new String(plainBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("私钥解密失败");
        }
    }

    /**
     * 私钥加密
     *
     * @param plaintext     原始数据
     * @param privateKey    私钥字符串（字节数组 Base64编码）
     * @return              明文字节数组，加密，Base64编码，再转字符串
     */
    public static String encryptByPri(String plaintext, String privateKey) {
        try {
            Cipher cipher = Cipher.getInstance(SELECTED_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(privateKey));
            byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            return new String(ENCODER64.encode(encryptedBytes), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("公钥加密失败");
        }
    }

    /**
     * 公钥解密
     *
     * @param encryptedStr  加密的字符串
     * @param publicKey     公钥字符串（字节数组 Base64解码）
     * @return              密文的字节数组，Base64解码，解密，再转字符串
     */
    public static String decryptByPub(String encryptedStr, String publicKey) {
        try {
            Cipher cipher = Cipher.getInstance(SELECTED_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, getPublicKey(publicKey));
            byte[] plainBytes = cipher.doFinal(DECODER64.decode(encryptedStr.getBytes(StandardCharsets.UTF_8)));
            return new String(plainBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("私钥解密失败");
        }
    }

    /**
     * 私钥字符串 生成 私钥对象：私钥的字节数组经过 base64解码
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        // 使用 私钥 生成 密钥规范（密钥材料）
        byte[] decode = DECODER64.decode(privateKey.getBytes(StandardCharsets.UTF_8));
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decode);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_CIPHER);

        // 使用密钥规范（密钥材料）生成私钥对象
        return keyFactory.generatePrivate(priPKCS8);
    }

    /**
     * 指定 RSA私钥各个参数的值（如模数、指数、系数等），并生成 私钥对象
     *
     * @param modulus           模数
     * @param publicExponent    公钥指数
     * @param privateExponent   私钥指数
     * @param primeP            质数 P
     * @param primeQ            质数 Q
     * @param primeExponentP    第一个指数 P，d mod (p-1)的逆元
     * @param primeExponentQ    第一个指数 Q，d mod (q-1)的逆元
     * @param crtCoefficient    中国余数定理系数 q-1 mod p
     *
     * @return
     * @throws Exception
     */
    public static java.security.interfaces.RSAPrivateCrtKey getPrivateKey(BigInteger modulus, BigInteger publicExponent, BigInteger privateExponent,
                                                 BigInteger primeP, BigInteger primeQ, BigInteger primeExponentP,
                                                 BigInteger primeExponentQ, BigInteger crtCoefficient) throws Exception {
        RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent,
                primeP, primeQ, primeExponentP, primeExponentQ, crtCoefficient);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return (sun.security.rsa.RSAPrivateCrtKeyImpl) factory.generatePrivate(keySpec);
    }

    /**
     * RSAPrivateKeyImpl 仅存储了RSA私钥的模数和指数参数，缺少了一些用于加速RSA解密操作的必需参数。
     * 因此，某些情况下，可能会导致解密操作的性能下降。
     *
     * @param modulus           模数
     * @param privateExponent   私钥指数
     */
    public static java.security.interfaces.RSAPrivateKey getPrivateKey2(BigInteger modulus, BigInteger privateExponent) throws Exception {
        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, privateExponent);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return (sun.security.rsa.RSAPrivateKeyImpl) factory.generatePrivate(keySpec);
    }

    /**
     * 公钥字符串 生成 公钥对象：公钥的字节数组经过 base64解码
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        // 使用 公钥 生成 密钥规范（密钥材料）
        byte[] decode = DECODER64.decode(publicKey.getBytes(StandardCharsets.UTF_8));
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decode);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_CIPHER, "SunRsaSign");

        // 使用密钥规范（密钥材料）生成公钥对象
        return keyFactory.generatePublic(x509KeySpec);
    }

    /**
     * 从 cert证书获取 公钥对象
     */
    public static PublicKey getPublicKeyFromCert(String certPath) {
        try {
            // 使用 公钥 生成 密钥规范（密钥材料）
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream inputStream = new FileInputStream(RSAUtil.class.getClassLoader().getResource(certPath).getPath());
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);

            // 使用密钥规范（密钥材料）生成公钥对象
            return cert.getPublicKey();
        } catch (CertificateException | FileNotFoundException e) {
            throw new RuntimeException("公钥文件读取失败！");
        }
    }

    /**
     * 字节数组转 String
     *
     * @param bytes
     * @return
     */
    private static String byteArr2Str(byte[] bytes) {
        return new String(ENCODER64.encode(bytes), StandardCharsets.UTF_8);
    }

    /**
     * 密钥对象（公私钥）转字符串
     *
     * @param key 密钥对象
     */
    public static String getKeyStr(Key key) {
        return new String(ENCODER64.encode(key.getEncoded()), StandardCharsets.UTF_8);
    }

    /**
     * 从密钥文件加载密钥对（公钥和私钥），pkcs#8格式
     */
    public static Map<String, Key> genKeyPair() throws Exception {
        // /** RSA算法要求有一个可信任的随机数源 */
        // SecureRandom sr = new SecureRandom();
        // KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA_CIPHER);
        // keyPairGen.initialize(SIZE_2048, sr);
        // KeyPair keyPair = keyPairGen.generateKeyPair();
        // RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // String priStr = new String(ENCODER64.encode(privateKey.getEncoded()), StandardCharsets.UTF_8);
        // IoUtil.writeToFile(PRIVATE_KEY_PATH, priStr);
        // String pubStr = new String(ENCODER64.encode(publicKey.getEncoded()), StandardCharsets.UTF_8);
        // IoUtil.writeToFile(PUBLIC_KEY_PATH, pubStr);
        //
        // BigInteger bInt = publicKey.getModulus();
        // byte[] b = bInt.toByteArray();
        // byte[] deBase64Value = org.apache.commons.codec.binary.Base64.encodeBase64(b);
        // String retValue = new String(deBase64Value);
        // map.put("modulus", retValue);

        // 从文件加载 PKCS#1 密钥
        java.security.interfaces.RSAPrivateKey privateKey = (java.security.interfaces.RSAPrivateKey) getPrivateKey(IoUtils.readFromFile(PRIVATE_KEY_PATH));
        System.out.println(privateKey);
        java.security.interfaces.RSAPublicKey publicKey = (java.security.interfaces.RSAPublicKey) getPublicKey(IoUtils.readFromFile(PUBLIC_KEY_PATH));


        Map<String, Key> keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;
    }

    /**
     * 生成没有加密的密钥对，pkcs#8格式（可转 pkcs#1格式）
     * 
     * @param algorithm
     * @param keySize
     * @return
     * @throws Exception
     */
    public static Map<String, RSAKey> createKey(String algorithm, int keySize) throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keySize, sr);
        KeyPair keyPair = keyPairGen.generateKeyPair();

        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        java.security.interfaces.RSAPublicKey publicKey = (java.security.interfaces.RSAPublicKey) keyPair.getPublic();
        java.security.interfaces.RSAPrivateKey privateKey = (java.security.interfaces.RSAPrivateKey) keyPair.getPrivate();

        //公私钥对象存入map中
        Map<String, RSAKey> keyMap = new HashMap<>(2);
        keyMap.put("publicKey", publicKey);
        keyMap.put("privateKey", privateKey);

        return keyMap;
    }

    /**
     * 生成加过密的密钥对，pkcs#8格式（可转 pkcs#1格式）
     *
     * @param algorithm     加密算法
     * @param keySize       RSA密钥长度（位数）
     * @param privateKeyPwd 加密私钥的密码
     * @return
     * @throws Exception
     */
    public static Map<String, String> createEncryptKeyStr(String algorithm, int keySize, String privateKeyPwd) throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keySize, sr);
        KeyPair keyPair = keyPairGen.generateKeyPair();

        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        java.security.interfaces.RSAPublicKey publicKey = (java.security.interfaces.RSAPublicKey) keyPair.getPublic();
        java.security.interfaces.RSAPrivateKey privateKey = (java.security.interfaces.RSAPrivateKey) keyPair.getPrivate();

        // pkcs8格式
        String pubKeyStr = new String(ENCODER64.encode(publicKey.getEncoded()), StandardCharsets.UTF_8);
        // pkcs8格式
        String priKeyStr = new String(ENCODER64.encode(privateKey.getEncoded()), StandardCharsets.UTF_8);
        // 从输出结果可以知道是 PKCS#8格式的
        System.out.println(priKeyStr);

        // 使用BC转换私钥格式：PKCS#8 --> PKCS#1格式
        System.out.println(privateKeyPKCS8ToPKCS1(privateKey));// 不带密码
        System.out.println(publicKeyPKCS8ToPKCS1(publicKey));// 不带密码
        // System.out.println(privateKeyWithPwdPKCS8ToPKCS1(privateKey, privateKeyPwd));// 带密码

        // 公私钥对象存入map中
        Map<String, String> keyMap = new HashMap<>(2);
        keyMap.put("publicKeyStr", pubKeyStr);
        keyMap.put("privateKeyStr", priKeyStr);
        return keyMap;
    }

    /**
     * 将 PKCS#8（没有加密）转为 PKCS#1格式：
     *  BEGIN PRIVATE KEY --> BEGIN RSA PRIVATE KEY
     *
     * @param privateKey    不带密码的私钥对象
     * @return
     */
    private static String privateKeyPKCS8ToPKCS1(PrivateKey privateKey){
        try {
            // 将BASE64编码的私钥字符串进行解码
            // byte[] encodeByte = DECODER64.decode(privateKeyStr);

            PrivateKeyInfo pki = PrivateKeyInfo.getInstance(privateKey.getEncoded());
            RSAPrivateKey pkcs1Key = RSAPrivateKey.getInstance(pki.parsePrivateKey());

            return byteArr2Str(pkcs1Key.getEncoded());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    /**
     * 私钥对象 转 PEM格式的 PKCS8
     */
    public static String priKey2Pkcs8Pem(PrivateKey privateKey, boolean isRsaNotEcc) throws IOException {
        PemObject pem = new PemObject(isRsaNotEcc ? "PRIVATE KEY" : "EC PRIVATE KEY", privateKey.getEncoded());
        StringWriter str = new StringWriter();
        PemWriter pemWriter = new PemWriter(str);
        pemWriter.writeObject(pem);
        pemWriter.close();
        str.close();
        return str.toString();
    }

    /**
     * 将 PKCS#8私钥（加密过的）转为 PKCS#1 格式：
     *  BEGIN PRIVATE KEY --> BEGIN RSA PRIVATE KEY
     *
     * @param privateKey    带密码的私钥对象
     * @param filePasswd    解密私钥文件的密码
     * @return
     */
    private static String privateKeyWithPwdPKCS8ToPKCS1(PrivateKey privateKey, String filePasswd) {
        try (StringWriter sw = new StringWriter(); PemWriter writer = new PemWriter(sw)) {
            PemObject pem = new PemObject("RSA PRIVATE KEY", privateKey.getEncoded());
            writer.writeObject(pem);

            return sw.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        throw new RuntimeException("error");
    }

    /**
     * （公钥） PKCS#8 转 PKCS#1格式：
     *  BEGIN PUBLIC KEY --> BEGIN RSA PUBLIC KEY
     *
     * @param key    不带密码的密钥对象
     * @return
     */
    private static String publicKeyPKCS8ToPKCS1(PublicKey key){
        ASN1Sequence publicKeyASN1Object = ASN1Sequence.getInstance(key.getEncoded());
        ASN1Encodable derBitStringASN1Encodable = publicKeyASN1Object.getObjectAt(1);
        DERBitString derBitStringObject = DERBitString.getInstance(derBitStringASN1Encodable);

        return byteArr2Str(derBitStringObject.getBytes());
    }

    /**
     * （私钥）byte数组 还原为 PKCS8私钥
     *
     * @param pkcs8PrivateKeyByte
     * @return
     */
    public static PrivateKey formatPKCS8PrivateKey(byte[] pkcs8PrivateKeyByte) {
        try {
            EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKeyByte);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new RuntimeException("字节数组转 PKCS8私钥 失败！");
    }

    /**
     * （公钥）byte数组 还原为 PKCS8公钥
     *
     * @param pkcs8PublicKeyByte
     * @return
     */
    public static PublicKey formatPKCS8PublicKey(byte[] pkcs8PublicKeyByte) {
        try {
            EncodedKeySpec keySpec = new X509EncodedKeySpec(pkcs8PublicKeyByte);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new RuntimeException("字节数组转 PKCS8公钥 失败！");
    }

    /**
     * （私钥）将 PKCS#1 转为 PKCS#8格式（与 `openssl pkcs8` 工具的转换结果比较，首行存在部分差异，据说不影响使用）：
     *      BEGIN PRIVATE KEY --> BEGIN RSA PRIVATE KEY
     *
     * @param pkcs1PriStr    pkcs1 私钥字符串
     * @return
     */
    private static String privateKeyPKCS1ToPKCS8(String pkcs1PriStr) {
        AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag);
        byte[] decode = DECODER64.decode(pkcs1PriStr.getBytes(StandardCharsets.UTF_8));
        RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(decode);

        try {
            PrivateKeyInfo priKeyInfo = new PrivateKeyInfo(algorithmIdentifier, rsaPrivateKey);
            byte[] pkcs8Bytes  = priKeyInfo.getEncoded();

            return byteArr2Str(pkcs8Bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    /**
     * （公钥）PKCS#1 转为 PKCS#8格式：
     *      BEGIN RSA PUBLIC KEY --> BEGIN PUBLIC KEY
     *
     * @param pkcs1PubStr    pkcs1 公钥字符串
     * @return
     */
    private static String publicKeyPKCS1ToPKCS8(String pkcs1PubStr) {
        try {
            byte[] decode = DECODER64.decode(pkcs1PubStr.getBytes(StandardCharsets.UTF_8));
            RSAPublicKey rsaPub = RSAPublicKey.getInstance(decode);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PublicKey generatePublic = kf.generatePublic(new RSAPublicKeySpec(rsaPub.getModulus(), rsaPub.getPublicExponent()));

            return byteArr2Str(generatePublic.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new RuntimeException("PKCS#1公钥 转 PKCS#8 失败！");
    }

    /**
     * （私钥）byte数组 还原为 PKCS1私钥
     *
     * @param pkcs1PrivateKeyByte
     * @return
     */
    public static RSAPrivateKey formatPKCS1PrivateKey(byte[] pkcs1PrivateKeyByte) {
        return RSAPrivateKey.getInstance(pkcs1PrivateKeyByte);
    }

    /**
     * （公钥）byte数组 还原为 PKCS1公钥
     *
     * @param pkcs1PublicKeyByte
     * @return
     */
    public static RSAPublicKey formatPKCS1PublicKey(byte[] pkcs1PublicKeyByte) {
        return RSAPublicKey.getInstance(pkcs1PublicKeyByte);
    }

}
